package com.sinodata.bsm.cicp.collector.file;

import java.io.BufferedReader;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.List;

import org.apache.log4j.Logger;

import com.sinodata.bsm.cicp.collector.Collector;
import com.sinodata.bsm.cicp.exception.CollectorException;
import com.sinodata.bsm.cicp.util.CollectorUtil;
import com.sinodata.bsm.cicp.util.CommandReader;
import com.sinodata.bsm.cicp.util.FileAttribute;
import com.sinodata.bsm.cicp.util.ProtocolParameterUtil;
import com.sinodata.bsm.common.constants.DataTypeConstants;
import com.sinodata.bsm.common.utils.FileUtil;
import com.sinodata.bsm.common.vo.ProtocolParameter;
import com.sinodata.bsm.common.vo.ResPropertyValue;

/**
 * 
 * <p>
 * Description: 日志文件内容监控(原日志文件过滤，替代原来的日志文件内容监控)
 *              目前适用于Linux、Unix机器文件内容监控 2012-11-22
 *              
 *              2012-12-20 间隔时间(Interval)改为 是否合并，默认为合并，界面传入“否”、“NO”、“0”、“不是” 均代表否
 *              
 *              
 * </p>
 *
 * @author liulibo
 * @version 1.0

 * <p>
 * History: 
 *
 * Date                     Author         Version     Description
 * ---------------------------------------------------------------------------------
 * 2012-11-22 17:33:41      liulibo        1.0         To create
 * </p>
 *
 * @since 
 * @see
 */
public class LogFileCollector extends Collector {

    private static Logger logger = Logger.getLogger(LogFileCollector.class);

    public LogFileCollector() {

    }

    /*
     * (non-Javadoc)
     * @see com.sinodata.bsm.cicp.collector.Collector#collect(java.lang.String)
     */
    @Override
    public List<ResPropertyValue> collect(String ip) throws CollectorException {
        if (this.getParamMeta() == null || this.getParamMeta().length < 3) {
            logger.error("parameter wrong, failed to collecte");
            return null;
        }
        String filePath = this.getParamMap().get("FilePath").trim();//文件路径
        String fileName = this.getParamMap().get("FilePattern").trim();//文件匹配正则表达式
        String errFlag = this.getParamMap().get("ErrorFlag").trim();//错误标识
        //是否合并判断开始
        boolean isMerge = true;
        String isMergeStr = this.getParamMap().get("Interval").trim();//是否合并
        if (isMergeStr != null) {
            if (isMergeStr.equals("否") || isMergeStr.equals("0") || isMergeStr.equals("NO") || isMergeStr.equals("不是")) {
                isMerge = false;
            }
        }
        //是否合并判断结束
        ProtocolParameter protocolParameter = ProtocolParameterUtil.getHostValue(ip);
        String filterDir = protocolParameter.getUrl();
        String fullFileName = getFullFileName(filePath, fileName);
        String tmpFileName = getTmpFileName(fullFileName, errFlag, ip);
        FileAttribute currentAttribute = CollectorUtil.getNewestRemoteFileByPattern(filePath, filterDir, fileName, ip);
        if (currentAttribute == null) {
            return null;
        }
        fileName = currentAttribute.name;
        fullFileName = getFullFileName(filePath, fileName);
        FileAttribute lastAttribute = (FileAttribute) FileUtil.readObjFromFile(tmpFileName);
        List<ResPropertyValue> result = null;
        String[] propMetas = getPropMeta();
        ResPropertyValue propertyValueX = new ResPropertyValue();
        ResPropertyValue.PropValue[] propValues = new ResPropertyValue.PropValue[propMetas.length];
        if (lastAttribute != null) {
            if (!currentAttribute.name.equals(lastAttribute.name)) {//文件名不相等，从头开始读
                result = readFile(fileName, filterDir, fullFileName, isMerge, 0, errFlag, ip, propertyValueX, propValues, propMetas);
            } else if (currentAttribute.size > lastAttribute.size) {//文件变化，从上一次记录值开始读
                result = readFile(fileName, filterDir, fullFileName, isMerge, lastAttribute.size, errFlag, ip, propertyValueX, propValues, propMetas);
            } else if (currentAttribute.size < lastAttribute.size) {//文件变小,从头开始读
                result = readFile(fileName, filterDir, fullFileName, isMerge, 0, errFlag, ip, propertyValueX, propValues, propMetas);
            } else {//文件相等返回未产生新错误
                result = new ArrayList<ResPropertyValue>();
                propValues[0] = ResPropertyValue.createPropValue(DataTypeConstants.BOOLEAN_VALUE_FALSE, propMetas[0]);
                propValues[1] = ResPropertyValue.createPropValue(fileName, propMetas[1]);
                propValues[2] = ResPropertyValue.createPropValue(" ", propMetas[2]);
                propValues[3] = ResPropertyValue.createPropValue("0", propMetas[3]);
                propertyValueX.setValues(propValues);
                result.add(propertyValueX);
            }
        } else {//lastAttribute 为空 第一次采集，返回未产生新错误
            result = new ArrayList<ResPropertyValue>();
            propValues[0] = ResPropertyValue.createPropValue(DataTypeConstants.BOOLEAN_VALUE_FALSE, propMetas[0]);
            propValues[1] = ResPropertyValue.createPropValue(fileName, propMetas[1]);
            propValues[2] = ResPropertyValue.createPropValue(" ", propMetas[2]);
            propValues[3] = ResPropertyValue.createPropValue("0", propMetas[3]);
            propertyValueX.setValues(propValues);
            result.add(propertyValueX);
        }

        // 记录文件位置
        if (lastAttribute == null || !lastAttribute.equals(currentAttribute)) {
            try {
                currentAttribute.lastTime = Calendar.getInstance().getTimeInMillis();
                FileUtil.forceWriteObjToFile(tmpFileName, currentAttribute, false);
            } catch (Exception e) {
                logger.error("failed to call " + this.getClass().getName() + ".collect()", e);
                throw new CollectorException(e);
            }
        }
        return result;
    }

    /**
     * 
     * 获取全文件文件名
     * 
     * @param path
     * @param fileName
     * @return
     */
    private String getFullFileName(String path, String fileName) {
        path = path.trim();
        if (path.endsWith("/")) {
            return path + fileName;
        } else {
            return path + "/" + fileName;
        }
    }

    /**
     * 获取临时文件的文件名
     * 
     * @param fileName
     * @param errFlag
     * @param ip
     * @return
     */
    private String getTmpFileName(String fileName, String errFlag, String ip) {
        String path = "tmp/";
        StringBuffer buffer = new StringBuffer();
        buffer.append(ip).append("_").append(fileName).append("_").append(errFlag);
        return path + FileUtil.validateFileName(buffer.toString());
    }

    /**
     * 从文件的某个位置开始读，直至文件结束
     *
     * @param fileName
     * @param readStart
     * @param ip
     * @return
     * @throws CollectorException
     */
    private List<ResPropertyValue> readFile(String fileName, String filterDir, String fullFileName, boolean isMerge, long readStart, String filterPattern, String ip, ResPropertyValue propertyValueX, ResPropertyValue.PropValue[] propValues, String[] propMetas) throws CollectorException {
        String cmd = "";
        if (filterDir != null && !filterDir.equals("")) {
            filterDir = filterDir.trim();
            if (!filterDir.endsWith("/")) {
                filterDir += "/";
            }
            cmd = filterDir + "filter -f " + fullFileName + " -s " + readStart;
        } else {
            cmd = "filter -f " + fullFileName + " -s " + readStart;
        }
        BufferedReader reader = null;
        if (filterPattern != null) {
            cmd = cmd + " -p '" + filterPattern + "'";
        }
        List<ResPropertyValue> result = new ArrayList<ResPropertyValue>();
        try {
            reader = CommandReader.getReader(ip, cmd, 0, 0);
            String line;
            boolean update = false;//start 2013-2-23 原机制为 相同内容进行合并， 修改为 只要检测到错误就和合并
            while ((line = reader.readLine()) != null) {
                line = line.trim();
                if (line.length() > 0) {
                    //2013-2-23 原机制为 相同内容进行合并， 修改为 只要检测到错误就和合并
                    if (isMerge) {//相同内容进行合并
                        //                        boolean update = false;
                        //                        for (ResPropertyValue resPropertyValue : result) {
                        //                            String temp = (resPropertyValue.getValues()[2]).value;
                        //                            if (temp != null && temp.equals(line)) {
                        //                                update = true;
                        //                                String countStr = resPropertyValue.getValues()[3].value;
                        //                                if (countStr != null && countStr.matches("\\d+")) {
                        //                                    int count = Integer.valueOf(countStr) + 1;
                        //                                    resPropertyValue.getValues()[3].value = count + "";//匹配到更新值
                        //                                }
                        //                                break;
                        //                            }
                        //                        }
                        //
                        //  end
                        if (!update) {//未匹配到认为是新记录
                            propertyValueX = new ResPropertyValue();
                            propValues = new ResPropertyValue.PropValue[propValues.length];
                            propValues[0] = ResPropertyValue.createPropValue(DataTypeConstants.BOOLEAN_VALUE_TRUE, propMetas[0]);
                            propValues[1] = ResPropertyValue.createPropValue(fileName, propMetas[1]);
                            propValues[2] = ResPropertyValue.createPropValue(line, propMetas[2]);
                            propValues[3] = ResPropertyValue.createPropValue("1", propMetas[3]);
                            propertyValueX.setValues(propValues);
                            result.add(propertyValueX);
                            update = true;// 单独加一行 2013-2-23 原机制为 相同内容进行合并， 修改为 只要检测到错误就和合并
                        }
                        // start 
                        if (result.size() <= 0) { //不会跑的代码
                            continue;
                        }
                        ResPropertyValue resPropertyValue = result.get(0);
                        if (resPropertyValue != null) {
                            String countStr = resPropertyValue.getValues()[3].value;
                            if (countStr != null && countStr.matches("\\d+")) {
                                int count = Integer.valueOf(countStr) + 1;
                                resPropertyValue.getValues()[3].value = count + "";//匹配到更新值
                            }
                        }
                        // end 2013-2-23 原机制为 相同内容进行合并， 修改为 只要检测到错误就和合并

                    } else { //不合并，每条都是一条
                        propertyValueX = new ResPropertyValue();
                        propValues = new ResPropertyValue.PropValue[propValues.length];
                        propValues[0] = ResPropertyValue.createPropValue(DataTypeConstants.BOOLEAN_VALUE_TRUE, propMetas[0]);
                        propValues[1] = ResPropertyValue.createPropValue(fileName, propMetas[1]);
                        propValues[2] = ResPropertyValue.createPropValue(line, propMetas[2]);
                        propValues[3] = ResPropertyValue.createPropValue("1", propMetas[3]);
                        propertyValueX.setValues(propValues);
                        result.add(propertyValueX);
                    }
                }
            }
            if (result.size() == 0) {//没有匹配到产生一条，未产生新错误
                propValues[0] = ResPropertyValue.createPropValue(DataTypeConstants.BOOLEAN_VALUE_FALSE, propMetas[0]);
                propValues[1] = ResPropertyValue.createPropValue(fileName, propMetas[1]);
                propValues[2] = ResPropertyValue.createPropValue(" ", propMetas[2]);
                propValues[3] = ResPropertyValue.createPropValue("0", propMetas[3]);
                propertyValueX.setValues(propValues);
                result.add(propertyValueX);
            }
            return result;
        } catch (IOException e) {
            logger.error("failed to call " + this.getClass().getName() + ".readFile()", e);
            throw new CollectorException(e);
        } finally {
            if (reader != null) {
                try {
                    reader.close();
                } catch (Exception ex) {
                    logger.error("failed to call " + this.getClass().getName() + ".readFile()", ex);
                    throw new CollectorException(ex);
                }
            }
        }
    }

    /*
     * (non-Javadoc)
     * @see com.sinodata.bsm.cicp.collector.Collector#getParamMeta()
     * FilePath              文件路径
     * FilePattern           文件匹配正则表达式
     * ErrorFlag             错误标识
     * Interval              时间间隔  改为  是否合并
     */
    @Override
    public String[] getParamMeta() {
        return new String[] { "FilePath", "FilePattern", "ErrorFlag", "Interval" };
    }

    /*
     * (non-Javadoc)
     * @see com.sinodata.bsm.cicp.collector.Collector#getPropMeta()
     * $1  isNewMistake  是否产生新错误
     * $2  fileName      文件匹配正则表达式
     * $3  Content       错误内容
     * $4  timeout       间隔时间内错误出现次数
     */
    @Override
    public String[] getPropMeta() {
        return new String[] { "$1", "$2", "$3", "$4" };
    }

}